﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Compilex.Automata;
using Infraestruturex.Automata.SPA;

namespace UnitTests.Lexic.FSA
{
    class TestAutomataCollection
    {

        public static A Get_a_2<A, S>()
            where S : IState<S>, new()
            where A : IAutomaton<S>, new()
        {
            // Aceita a^n, n > 0
            S startState = new S();
            S middleState = new S();
            S endState = new S(); endState.IsAcceptState = true;
            startState.AddTransition("a", middleState);
            middleState.AddTransition("a", endState);

            A automaton = new A();
            automaton.StartState = startState;
            return automaton;
            
        }

        public static A Get_a_N<A, S>()
            where S : IState<S>, new()
            where A : IAutomaton<S>, new()
        {
            // Aceita a^n, n > 0
            S startState = new S();
            S endState = new S(); endState.IsAcceptState = true;
            startState.AddTransition("a", endState);
            endState.AddTransition("a", endState);

            A automaton = new A();
            automaton.StartState = startState;
            return automaton;
        }

        /// <summary>
        /// Aceita cadeias de "1" e "0" que tenham um número ímpar de zeros.
        /// </summary>
        /// <returns></returns>
        public static A GetOddNumberOfZeroes<A, S>()
            where S : IState<S>, new()
            where A : IAutomaton<S>, new()
        {
            S startState = new S();
            S endState = new S();
            
            endState.IsAcceptState = true;

            startState.AddTransition("0", endState);
            startState.AddTransition("1", startState);

            endState.AddTransition("0", startState);
            endState.AddTransition("1", endState);

            A a = new A();
            a.StartState = startState;
            return a;
        }

        /// <summary>
        /// Aceita cadeias binárias que contêm "001".
        /// Fonte: Sipser pág. 44
        /// </summary>
        /// <returns></returns>
        public static A GetContains001<A, S>()
            where S : IState<S>, new()
            where A : IAutomaton<S>, new()
        {
            S q = new S();
            S q0 = new S();
            S q00 = new S();
            S q001 = new S();
            q001.IsAcceptState = true;

            q.AddTransition("1", q);
            q.AddTransition("0", q0);

            q0.AddTransition("1", q);
            q0.AddTransition("0", q00);

            q00.AddTransition("0", q00);
            q00.AddTransition("1", q001);

            q001.AddTransition("0", q001);
            q001.AddTransition("1", q001);

            A automaton = new A();
            automaton.StartState = q;
            return automaton;
        }

        public static NFA ThirdFromBackIs1()
        {
            NFAState q1 = new NFAState("q1");
            NFAState q2 = new NFAState("q2");
            NFAState q3 = new NFAState("q3");
            NFAState q4 = new NFAState("q4", true);

            q1.AddTransition("0", q1);
            q1.AddTransition("1", q1);

            q1.AddTransition("1", q2);

            q2.AddTransition("0", q3);
            q2.AddTransition("1", q3);

            q3.AddTransition("0", q4);
            q3.AddTransition("1", q4);

            return new NFA(q1);
        }

        public static NFA ZeroKmultiple2n3()
        {
            NFAState q1 = new NFAState("q1");
            NFAState q2 = new NFAState("q2", true);
            NFAState q3 = new NFAState("q3");
            NFAState q4 = new NFAState("q4", true);
            NFAState q5 = new NFAState("q5");
            NFAState q6 = new NFAState("q6");

            q1.AddEpsilonTransition(q2);
            q1.AddEpsilonTransition(q4);

            q2.AddTransition("0", q3);
            q3.AddTransition("0", q2);

            q4.AddTransition("0", q5);
            q5.AddTransition("0", q6);
            q6.AddTransition("0", q4);

            return new NFA(q1);
        }

        public static NFA Contains101or11()
        {
            NFAState q1 = new NFAState("q1");
            NFAState q2 = new NFAState("q2");
            NFAState q3 = new NFAState("q3");
            NFAState q4 = new NFAState("q4", true);

            q1.AddTransition("0", q1);
            q1.AddTransition("1", q1);
            q1.AddTransition("1", q2);

            q2.AddTransition("0", q3);
            q2.AddEpsilonTransition(q3);

            q3.AddTransition("1", q4);

            q4.AddTransition("0", q4);
            q4.AddTransition("1", q4);

            return new NFA(q1);
        }

        public static SPA bNabN()
        {
            SPA spa = new SPA("bNabN");

            SPAState A = new SPAState("A");
            SPAState B = new SPAState("B");
            SPAState C = new SPAState("C");
            SPAState D = new SPAState("D", true);

            A.AddTransition("a", D);
            A.AddTransition("b", B);

            B.IsSubmachineCallState = true;
            B.SubmachineCallReturnState = C;
            B.SubmachineToCall = spa;

            C.AddTransition("b", D);

            spa.StartState = A;
            return spa;
            
        }
    }
}
